﻿#if UNITY_EDITOR

using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Core;

[CustomEditor(typeof(ReferenceGroup))]
public class ReferenceGroupEditor : Editor
{
    static FieldInfo referencesInfo;
    static List<GameObject> conflicts = new List<GameObject>();

    [InitializeOnLoadMethod]
    public static void ListenApplyEvent()
    {
        referencesInfo = typeof(ReferenceGroup).GetField("references", BindingFlags.Instance | BindingFlags.NonPublic);

        UnityEditor.SceneManagement.PrefabStage.prefabSaving -= OnPrefabSaving;
        UnityEditor.SceneManagement.PrefabStage.prefabSaving += OnPrefabSaving;
    }

    public static void OnPrefabSaving(GameObject operateObj)
    {
        var rg = operateObj.GetComponent<ReferenceGroup>();

        conflicts.Clear();
        UpdateReference(rg);
        if (conflicts.Count > 0)
        {
            Selection.objects = conflicts.ToArray();
            return;
        }
    }

    [MenuItem("GameObject/Reference/AddGroup(F5) _F5", priority = 0)]
    public static void AddReferenceGroup()
    {
        GameObject selectObj = Selection.activeGameObject;
        if (selectObj == null)
            return;

        if (selectObj.GetComponent<ReferenceUnit>() != null)
            DestroyImmediate(selectObj.GetComponent<ReferenceUnit>());

        if (selectObj.GetComponent<ReferenceGroup>() == null)
            selectObj.AddComponent<ReferenceGroup>();

        if (selectObj.transform.parent != null)
            UpdateReference(selectObj.transform.parent.GetComponentInParent<ReferenceGroup>());

        EditorUtility.SetDirty(selectObj);
    }

    [MenuItem("GameObject/Reference/RemoveGroup(F7) _F7", priority = 2)]
    public static void RemoveReferenceGroup()
    {
        GameObject selectObj = Selection.activeGameObject;
        if (selectObj == null)
            return;

        var g = selectObj.GetComponent<ReferenceGroup>();
        if (g != null)
            DestroyImmediate(g);

        if (selectObj.transform.parent != null)
            UpdateReference(selectObj.transform.parent.GetComponentInParent<ReferenceGroup>());

        EditorUtility.SetDirty(selectObj);
    }

    [MenuItem("GameObject/Reference/AddUnit(F6) _F6", priority = 1)]
    public static void AddReferenceUnit()
    {
        GameObject selectObj = Selection.activeGameObject;
        if (selectObj == null)
            return;

        if (selectObj.GetComponent<ReferenceUnit>() == null)
            selectObj.AddComponent<ReferenceUnit>();

        if (selectObj.transform.parent != null)
            UpdateReference(selectObj.transform.parent.GetComponentInParent<ReferenceGroup>());

        EditorUtility.SetDirty(selectObj);
    }

    [MenuItem("GameObject/Reference/RemoveUnit(F8) _F8", priority = 3)]
    public static void RemoveReferenceUnit()
    {
        GameObject selectObj = Selection.activeGameObject;
        if (selectObj == null)
            return;

        ReferenceUnit unit = selectObj.GetComponent<ReferenceUnit>();
        if (unit != null)
            DestroyImmediate(unit);

        if (selectObj.transform.parent != null)
            UpdateReference(selectObj.transform.parent.GetComponentInParent<ReferenceGroup>());

        EditorUtility.SetDirty(selectObj);
    }

    public override void OnInspectorGUI()
    {
        var list = (List<ReferenceGroup.Data>)referencesInfo.GetValue(target);

        if (list == null)
            return;

        if (GUILayout.Button("刷新"))
        {
            conflicts.Clear();
            UpdateReference(target as ReferenceGroup);

            EditorUtility.SetDirty(target);
        }

        foreach (var item in list)
        {
            using (new GUILayout.HorizontalScope())
            {
                EditorGUILayout.ObjectField(item.name, item.go, typeof(GameObject), true);

                if (GUILayout.Button("Copy", GUILayout.Width(50)))
                    GUIUtility.systemCopyBuffer = item.name;
            }
            
        }
    }

    static void UpdateReference(ReferenceGroup rg)
    {
        if (rg == null)
            return;

        var gameObjects = GetUnits(rg.gameObject);

        var dic = new Dictionary<string, bool>();
        var list = new List<ReferenceGroup.Data>();

        foreach (var unit in gameObjects)
        {
            if(dic.ContainsKey(unit.name))
            {
                Debug.LogError($"重名物体：{unit.name}");
                conflicts.Add(unit);
                continue;
            }

            dic[unit.name] = true;

            if (conflicts.Count > 0)
                continue;

            list.Add(new ReferenceGroup.Data()
            {
                name = unit.name,
                go = unit
            });
        }

        if (conflicts.Count > 0)
            return;

        referencesInfo.SetValue(rg, list);
    }


    static List<GameObject> GetUnits(GameObject root)
    {
        var list = new List<GameObject>();

        for (int i = 0; i < root.transform.childCount; i++)
        {
            var child = root.transform.GetChild(i);

            var unit = child.GetComponent<ReferenceUnit>();
            if (unit != null)
                list.Add(unit.gameObject);

            if (child.transform.childCount == 0)
                continue;

            // 不包含物体引用类
            if (child.GetComponent<GameReference>())
                continue;

            // 不包含子类
            var rg = child.GetComponent<ReferenceGroup>();
            if (rg != null)
            {
                UpdateReference(rg);
                continue;
            }

            list.AddRange(GetUnits(child.gameObject));
        }

        return list;
    }


}
#endif